package com.graduation.service.impl;

import cn.hutool.core.util.StrUtil;
import com.graduation.common.domain.dto.PageDTO;
import com.graduation.pojo.po.LegalDocument;
import com.graduation.pojo.query.LegalDocumentSearchQuery;
import com.graduation.pojo.vo.LegalDocumentSearchVO;
import com.graduation.service.ElasticSearchService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.client.elc.NativeQuery;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import com.graduation.common.constans.EsConstants;
import org.springframework.stereotype.Service;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;

import java.util.ArrayList;
import java.util.List;

@Slf4j
@Service
@RequiredArgsConstructor
public class ElasticSearchServiceImpl implements ElasticSearchService {

    private final ElasticsearchOperations elasticsearchOperations;

    @Override
    public void handleEsSaveLegalDocument(LegalDocument legalDocument) {
        try {
            // 保存
            elasticsearchOperations.save(legalDocument);
            log.info("保存文档到ES成功，文档ID：{}", legalDocument.getId());
        } catch (Exception e) {
            log.error("保存文档到ES失败", e);
        }
    }

    @Override
    public void handleEsUpdateLegalDocument(LegalDocument legalDocument) {
        try {
            // 更新操作和保存操作一样，ES会根据ID判断是新增还是更新
            elasticsearchOperations.save(legalDocument);
            log.info("更新ES文档成功，文档ID：{}", legalDocument.getId());
        } catch (Exception e) {
            log.error("更新ES文档失败", e);
        }
    }

    @Override
    public void handleEsDeleteLegalDocument(Long id) {
        try {
            elasticsearchOperations.delete(id.toString(), IndexCoordinates.of(EsConstants.LEGAL_DOCUMENT_INDEX));
            log.info("删除ES文档成功，文档ID：{}", id);
        } catch (Exception e) {
            log.error("删除ES文档失败", e);
        }
    }

    @Override
    public PageDTO<LegalDocumentSearchVO> searchLegalDocument(LegalDocumentSearchQuery query) {
        // 构建查询
        NativeQuery searchQuery = buildSearchQuery(query);

        // 执行搜索
        SearchHits<LegalDocument> searchHits = elasticsearchOperations.search(
                searchQuery, LegalDocument.class, IndexCoordinates.of(EsConstants.LEGAL_DOCUMENT_INDEX)
        );

        // 转换结果
        List<LegalDocumentSearchVO> records = convertToSearchVO(searchHits, query.getKey());

        // 计算总页数
        long total = searchHits.getTotalHits();
        long pages = (total + query.getPageSize() - 1) / query.getPageSize();

        log.info("ES搜索完成，关键词：{}，总记录数：{}，当前页：{}", query.getKey(), total, query.getPageNum());
        return PageDTO.of(pages, total, records);
    }

    /**
     * 构建搜索查询
     */
    private NativeQuery buildSearchQuery(LegalDocumentSearchQuery query) {
        // 构建ES查询
        Query esQuery;

        if (StrUtil.isNotBlank(query.getKey())) {
            // 多字段搜索
            Query multiMatchQuery = Query.of(q -> q
                    .multiMatch(m -> m
                            .query(query.getKey())
                            .fields("title^2.0", "content^1.0", "keywords^1.5")
                    )
            );

            // 如果有文档类型过滤，添加布尔查询
            if (query.getDocType() != null) {
                esQuery = Query.of(q -> q
                        .bool(b -> b
                                .must(multiMatchQuery)
                                .filter(f -> f.term(t -> t.field("docType").value(query.getDocType())))
                        )
                );
            } else {
                esQuery = multiMatchQuery;
            }
        } else if (query.getDocType() != null) {
            // 只有文档类型过滤
            esQuery = Query.of(q -> q
                    .term(t -> t.field("docType").value(query.getDocType()))
            );
        } else {
            // 查询所有
            esQuery = Query.of(q -> q.matchAll(m -> m));
        }

        return NativeQuery.builder()
                .withQuery(esQuery)
                .withSort(Sort.by(Sort.Direction.DESC, "publishDate"))
                .withPageable(PageRequest.of(query.getPageNum() - 1, query.getPageSize()))
                .build();
    }

    /**
     * 转换搜索结果为VO对象
     */
    private List<LegalDocumentSearchVO> convertToSearchVO(SearchHits<LegalDocument> searchHits, String keyword) {
        List<LegalDocumentSearchVO> records = new ArrayList<>();

        for (SearchHit<LegalDocument> hit : searchHits) {
            LegalDocument document = hit.getContent();
            LegalDocumentSearchVO vo = new LegalDocumentSearchVO();

            // 复制基本属性
            BeanUtils.copyProperties(document, vo);

            // 处理高亮结果
            List<String> titleHighlights = hit.getHighlightField("title");
            if (!titleHighlights.isEmpty()) {
                vo.setTitle(titleHighlights.get(0));
            } else if (StrUtil.isNotBlank(keyword)) {
                // 如果没有高亮但有关键词，手动添加高亮
                vo.setTitle(highlightText(document.getTitle(), keyword));
            }

            List<String> contentHighlights = hit.getHighlightField("content");
            if (!contentHighlights.isEmpty()) {
                // 取前2个高亮片段拼接
                StringBuilder contentBuilder = new StringBuilder();
                for (int i = 0; i < Math.min(contentHighlights.size(), 2); i++) {
                    if (i > 0) contentBuilder.append("...");
                    contentBuilder.append(contentHighlights.get(i));
                }
                vo.setContent(contentBuilder.toString());
            } else if (StrUtil.isNotBlank(keyword)) {
                // 如果没有高亮但有关键词，手动添加高亮并截取内容
                String highlightedContent = highlightText(document.getContent(), keyword);
                vo.setContent(truncateContent(highlightedContent, keyword));
            } else if (StrUtil.isNotBlank(document.getContent())) {
                // 没有关键词时截取前300个字符
                vo.setContent(document.getContent().length() > 300 ? 
                    document.getContent().substring(0, 300) + "..." : document.getContent());
            }

            List<String> keywordsHighlights = hit.getHighlightField("keywords");
            if (!keywordsHighlights.isEmpty()) {
                vo.setKeywords(keywordsHighlights.get(0));
            } else if (StrUtil.isNotBlank(keyword)) {
                // 如果没有高亮但有关键词，手动添加高亮
                vo.setKeywords(highlightText(document.getKeywords(), keyword));
            }

            records.add(vo);
        }

        return records;
    }

    /**
     * 手动高亮文本
     */
    private String highlightText(String text, String keyword) {
        if (StrUtil.isBlank(text) || StrUtil.isBlank(keyword)) {
            return text;
        }
        // 使用正则表达式进行大小写不敏感的替换
        return text.replaceAll("(?i)" + keyword, "<span class=\"high-light\">" + keyword + "</span>");
    }

    /**
     * 截取包含关键词的内容片段
     */
    private String truncateContent(String content, String keyword) {
        if (StrUtil.isBlank(content)) {
            return content;
        }
        
        // 查找关键词位置
        int keywordIndex = content.toLowerCase().indexOf(keyword.toLowerCase());
        if (keywordIndex == -1) {
            // 没有找到关键词，返回前maxLength个字符
            return content.length() > 300 ? content.substring(0, 300) + "..." : content;
        }
        
        // 计算截取的开始和结束位置
        int start = Math.max(0, keywordIndex - 300 / 3);
        int end = Math.min(content.length(), start + 300);
        
        String result = content.substring(start, end);
        if (start > 0) {
            result = "..." + result;
        }
        if (end < content.length()) {
            result = result + "...";
        }
        
        return result;
    }
}
